package com.yiyuan.app.service.impl;

import com.guaike.core.entity.enums.EnableStatusEnum;
import com.guaike.core.entity.result.Result;
import com.guaike.core.redis.context.ApiContext;
import com.yiyuan.app.dao.*;
import com.yiyuan.app.entity.enums.RankCodeEnum;
import com.yiyuan.app.entity.enums.RankTypeEnum;
import com.yiyuan.app.entity.enums.WeekTypeEnum;
import com.yiyuan.app.entity.param.RankDTO;
import com.yiyuan.app.entity.po.*;
import com.yiyuan.app.entity.result.AppUser;
import com.yiyuan.app.entity.result.BaseRankVO;
import com.yiyuan.app.entity.result.RankVO;
import com.yiyuan.app.service.RankService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class RankServiceImpl implements RankService {

    private final MRankPineconeDAO mRankPineconeDAO;
    private final UAppUserDAO uAppUserDAO;
    private final UAppUserEquityDAO uAppUserEquityDAO;
    private final MRankRichDAO mRankRichDAO;
    private final MConfRankDAO mConfRankDAO;
    private final MConfRankPrizeDAO mConfRankPrizeDAO;
    private final MRankPushCoinsDAO mRankPushCoinsDAO;
    private final MRankArcadeMachineDAO mRankArcadeMachineDAO;


    @Override
    public Result<RankVO> pineconeRankList(RankDTO param) {
        if (Objects.isNull(WeekTypeEnum.getByCode(param.getWeekType()))) {
            return Result.failure().message("日期类型不正确").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        LocalDate now = LocalDate.now();
        LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate endOfWeek = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

        LocalDate startOfLastWeek = startOfWeek.minusWeeks(1);
        LocalDate endOfLastWeek = endOfWeek.minusWeeks(1);
        UAppUserPO myPO = uAppUserDAO.findById(currentUser.getUserId());
        UAppUserEquityPO myEquityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        RankVO result = new RankVO();
        result.setNickName(myPO.getNickname());
        result.setAvatarurl(myPO.getAvatarurl());
        result.setVipGrade(myEquityPO.getVipGrade());
        List<BaseRankVO> rankVOS = new ArrayList<>();
        if (WeekTypeEnum.week.getCode().equals(param.getWeekType())) {
            result.setValue(myEquityPO.getPinecone().toString());
            List<UAppUserEquityPO> pos = uAppUserEquityDAO.findWeekPineconeRank();
            for (int i = 0; i < pos.size(); i++) {
                UAppUserEquityPO po = pos.get(i);
                BaseRankVO vo = new BaseRankVO();
                UAppUserPO userPO = uAppUserDAO.findById(po.getUserId());
                vo.setNickName(userPO.getNickname());
                vo.setAvatarurl(userPO.getAvatarurl());
                vo.setVipGrade(po.getVipGrade());
                vo.setValue(po.getPinecone().toString());
                vo.setRank(i + 1);
                if (po.getUserId().equals(currentUser.getUserId())) {
                    result.setIsRank(Boolean.TRUE);
                    result.setRank(i + 1);
                }
                rankVOS.add(vo);
            }
            result.setRankVOS(rankVOS);
            if (!result.getIsRank()) {
                BaseRankVO rankVO = null;
                if (CollectionUtils.isNotEmpty(rankVOS)) {
                    rankVO = rankVOS.get(rankVOS.size() - 1);
                }
                String diff = String.valueOf(Math.subtractExact(Integer.parseInt(Objects.isNull(rankVO) ? "0" : rankVO.getValue()), myEquityPO.getPinecone()));
                result.setDiff(diff);
            }
        } else if (WeekTypeEnum.yes_week.getCode().equals(param.getWeekType())) {
            List<MRankPineconePO> rankList = mRankPineconeDAO.findRankList(startOfLastWeek, endOfLastWeek);
            rankList.forEach(po -> {
                BaseRankVO vo = new BaseRankVO();
                vo.setNickName(po.getNickname());
                vo.setAvatarurl(po.getAvatarurl());
                vo.setVipGrade(po.getVipGrade());
                vo.setValue(po.getPinecone().toString());
                vo.setRank(po.getRankNo());
                if (po.getUserId().equals(currentUser.getUserId())) {
                    result.setIsRank(Boolean.TRUE);
                    result.setNickName(po.getNickname());
                    result.setAvatarurl(po.getAvatarurl());
                    result.setVipGrade(po.getVipGrade());
                    result.setValue(po.getPinecone().toString());
                    result.setRank(po.getRankNo());
                }
                rankVOS.add(vo);
            });
            result.setRankVOS(rankVOS);
        }
        return Result.success().data(result).build();
    }

    @Override
    public Result<RankVO> richRankList(RankDTO param) {
        if (Objects.isNull(WeekTypeEnum.getByCode(param.getWeekType()))) {
            return Result.failure().message("日期类型不正确").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        LocalDate today = LocalDate.now();
        LocalDate yesterday = today.minusDays(1);
        UAppUserPO myPO = uAppUserDAO.findById(currentUser.getUserId());
        UAppUserEquityPO myEquityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        RankVO result = new RankVO();
        result.setNickName(myPO.getNickname());
        result.setAvatarurl(myPO.getAvatarurl());
        result.setVipGrade(myEquityPO.getVipGrade());
        List<BaseRankVO> rankVOS = new ArrayList<>();
        if (WeekTypeEnum.week.getCode().equals(param.getWeekType())) {
            MConfRankPO confRankPO = mConfRankDAO.findOne(MConfRankPO::getRankCode, RankCodeEnum.hq.getCode());
            if (EnableStatusEnum.DISABLE.getCode().equals(confRankPO.getStatus())) {
                return Result.failure().message("排行榜配置维护中").build();
            }
            List<MConfRankPrizePO> prizePOS = mConfRankPrizeDAO.findList(MConfRankPrizePO::getRankId, confRankPO.getId(), MConfRankPrizePO::getRankNo, Boolean.TRUE);
            Map<Integer, List<MConfRankPrizePO>> listMap = prizePOS.stream().collect(Collectors.groupingBy(MConfRankPrizePO::getRankNo));
            List<MRankRichPO> pos = mRankRichDAO.findTodayRankList(today, prizePOS.size());
            for (int i = 0; i < pos.size(); i++) {
                MRankRichPO po = pos.get(i);
                List<MConfRankPrizePO> poList = listMap.get(i + 1);
                BaseRankVO vo = new BaseRankVO();
                UAppUserPO userPO = uAppUserDAO.findById(po.getUserId());
                vo.setNickName(userPO.getNickname());
                vo.setAvatarurl(userPO.getAvatarurl());
                vo.setVipGrade(po.getVipGrade());
                vo.setValue(po.getRechargeMoney().toPlainString());
                vo.setPrize(poList.get(0).getPinecone());
                vo.setRank(i + 1);
                if (po.getUserId().equals(currentUser.getUserId())) {
                    result.setIsRank(Boolean.TRUE);
                    result.setNickName(po.getNickname());
                    result.setAvatarurl(po.getAvatarurl());
                    result.setVipGrade(po.getVipGrade());
                    result.setValue(po.getRechargeMoney().toPlainString());
                    result.setPrize(poList.get(0).getPinecone());
                    result.setRank(i + 1);
                }
                rankVOS.add(vo);
            }
            result.setRankVOS(rankVOS);
            if (!result.getIsRank()) {
                MRankRichPO myRank = mRankRichDAO.findUserRank(today, currentUser.getUserId());
                BigDecimal myRecharge = Objects.isNull(myRank) ? new BigDecimal(0) : myRank.getRechargeMoney();
                BaseRankVO rankVO = null;
                if (CollectionUtils.isNotEmpty(rankVOS)) {
                    rankVO = rankVOS.get(rankVOS.size() - 1);
                }
                String diff = new BigDecimal(Objects.isNull(rankVO) ? "0" : rankVO.getValue()).subtract(myRecharge).toPlainString();
                result.setDiff(diff);
            }
        } else if (WeekTypeEnum.yes_week.getCode().equals(param.getWeekType())) {
            List<MRankRichPO> pos = mRankRichDAO.findYesRankList(yesterday);
            pos.forEach(po -> {
                BaseRankVO vo = new BaseRankVO();
                vo.setNickName(po.getNickname());
                vo.setAvatarurl(po.getAvatarurl());
                vo.setVipGrade(po.getVipGrade());
                vo.setValue(po.getRechargeMoney().toPlainString());
                vo.setPrize(po.getGetPinecone());
                vo.setRank(po.getRankNo());
                if (po.getUserId().equals(currentUser.getUserId())) {
                    result.setIsRank(Boolean.TRUE);
                    result.setNickName(po.getNickname());
                    result.setAvatarurl(po.getAvatarurl());
                    result.setVipGrade(po.getVipGrade());
                    result.setValue(po.getRechargeMoney().toPlainString());
                    result.setPrize(po.getGetPinecone());
                    result.setRank(po.getRankNo());
                }
                rankVOS.add(vo);
            });
            result.setRankVOS(rankVOS);
        }
        return Result.success().data(result).build();
    }

    @Override
    public Result<RankVO> pushCoinsRankList(RankDTO param) {
        if (Objects.isNull(WeekTypeEnum.getByCode(param.getWeekType()))) {
            return Result.failure().message("日期类型不正确").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        LocalDate now = LocalDate.now();
        LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate endOfWeek = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

        LocalDate startOfLastWeek = startOfWeek.minusWeeks(1);
        LocalDate endOfLastWeek = endOfWeek.minusWeeks(1);
        UAppUserPO myPO = uAppUserDAO.findById(currentUser.getUserId());
        UAppUserEquityPO myEquityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        RankVO result = new RankVO();
        result.setNickName(myPO.getNickname());
        result.setAvatarurl(myPO.getAvatarurl());
        result.setVipGrade(myEquityPO.getVipGrade());
        List<BaseRankVO> rankVOS = new ArrayList<>();
        if (WeekTypeEnum.week.getCode().equals(param.getWeekType())) {
            MConfRankPO confRankPO = mConfRankDAO.findOne(MConfRankPO::getRankCode, RankCodeEnum.gs.getCode());
            if (EnableStatusEnum.DISABLE.getCode().equals(confRankPO.getStatus())) {
                return Result.failure().message("排行榜配置维护中").build();
            }
            List<MConfRankPrizePO> prizePOS = mConfRankPrizeDAO.findList(MConfRankPrizePO::getRankId, confRankPO.getId(), MConfRankPrizePO::getRankNo, Boolean.TRUE);
            Map<Integer, List<MConfRankPrizePO>> listMap = prizePOS.stream().collect(Collectors.groupingBy(MConfRankPrizePO::getRankNo));
            List<MRankPushCoinsPO> pos = mRankPushCoinsDAO.findWeekRankList(startOfWeek, endOfWeek, prizePOS.size());
            for (int i = 0; i < pos.size(); i++) {
                MRankPushCoinsPO po = pos.get(i);
                List<MConfRankPrizePO> poList = listMap.get(i + 1);
                BaseRankVO vo = new BaseRankVO();
                UAppUserPO userPO = uAppUserDAO.findById(po.getUserId());
                vo.setNickName(userPO.getNickname());
                vo.setAvatarurl(userPO.getAvatarurl());
                vo.setVipGrade(po.getVipGrade());
                vo.setValue(po.getPushCoinsValue().toString());
                vo.setPrize(poList.get(0).getPinecone());
                vo.setRank(i + 1);
                if (po.getUserId().equals(currentUser.getUserId())) {
                    result.setIsRank(Boolean.TRUE);
                    result.setNickName(po.getNickname());
                    result.setAvatarurl(po.getAvatarurl());
                    result.setVipGrade(po.getVipGrade());
                    result.setValue(po.getPushCoinsValue().toString());
                    result.setPrize(poList.get(0).getPinecone());
                    result.setRank(i + 1);
                }
                rankVOS.add(vo);
            }
            result.setRankVOS(rankVOS);
            if (!result.getIsRank()) {
                MRankPushCoinsPO myRank = mRankPushCoinsDAO.findUserRank(startOfWeek, endOfWeek, currentUser.getUserId());
                int myPushCoins = Objects.isNull(myRank) ? 0 : myRank.getPushCoinsValue();
                BaseRankVO rankVO = null;
                if (CollectionUtils.isNotEmpty(rankVOS)) {
                    rankVO = rankVOS.get(rankVOS.size() - 1);
                }
                String diff = String.valueOf(Math.subtractExact(Integer.parseInt(Objects.isNull(rankVO) ? "0" : rankVO.getValue()), myPushCoins));
                result.setDiff(diff);
            }
        } else if (WeekTypeEnum.yes_week.getCode().equals(param.getWeekType())) {
            List<MRankPushCoinsPO> pos = mRankPushCoinsDAO.findYesWeekRankList(startOfLastWeek, endOfLastWeek);
            pos.forEach(po -> {
                BaseRankVO vo = new BaseRankVO();
                vo.setNickName(po.getNickname());
                vo.setAvatarurl(po.getAvatarurl());
                vo.setVipGrade(po.getVipGrade());
                vo.setValue(po.getPushCoinsValue().toString());
                vo.setPrize(po.getGetPinecone());
                vo.setRank(po.getRankNo());
                if (po.getUserId().equals(currentUser.getUserId())) {
                    result.setIsRank(Boolean.TRUE);
                    result.setNickName(po.getNickname());
                    result.setAvatarurl(po.getAvatarurl());
                    result.setVipGrade(po.getVipGrade());
                    result.setValue(po.getPushCoinsValue().toString());
                    result.setPrize(po.getGetPinecone());
                    result.setRank(po.getRankNo());
                }
                rankVOS.add(vo);
            });
            result.setRankVOS(rankVOS);
        }
        return Result.success().data(result).build();
    }

    @Override
    public Result<RankVO> arcadeMachineRankList(RankDTO param) {
        if (Objects.isNull(param.getTimesType())) {
            return Result.failure().message("倍数类型不能为空").build();
        }
        AppUser currentUser = ApiContext.getCurrentUser();
        LocalDate now = LocalDate.now();
        LocalDate startOfWeek = now.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
        LocalDate endOfWeek = now.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));

        LocalDate startOfLastWeek = startOfWeek.minusWeeks(1);
        LocalDate endOfLastWeek = endOfWeek.minusWeeks(1);
        UAppUserPO myPO = uAppUserDAO.findById(currentUser.getUserId());
        UAppUserEquityPO myEquityPO = uAppUserEquityDAO.findOne(UAppUserEquityPO::getUserId, currentUser.getUserId());
        RankVO result = new RankVO();
        result.setNickName(myPO.getNickname());
        result.setAvatarurl(myPO.getAvatarurl());
        result.setVipGrade(myEquityPO.getVipGrade());
        List<BaseRankVO> rankVOS = new ArrayList<>();
        if (WeekTypeEnum.week.getCode().equals(param.getWeekType())) {
            MConfRankPO confRankPO = null;
            if (param.getTimesType().equals(RankTypeEnum.low_machine.getCode())) {
                confRankPO = mConfRankDAO.findOne(MConfRankPO::getRankCode, RankCodeEnum.cw_low.getCode());
                if (EnableStatusEnum.DISABLE.getCode().equals(confRankPO.getStatus())) {
                    return Result.failure().message("排行榜配置维护中").build();
                }
            } else if (param.getTimesType().equals(RankTypeEnum.high_machine.getCode())) {
                confRankPO = mConfRankDAO.findOne(MConfRankPO::getRankCode, RankCodeEnum.cw_high.getCode());
                if (EnableStatusEnum.DISABLE.getCode().equals(confRankPO.getStatus())) {
                    return Result.failure().message("排行榜配置维护中").build();
                }
            }
            List<MConfRankPrizePO> prizePOS = mConfRankPrizeDAO.findList(MConfRankPrizePO::getRankId, confRankPO.getId(), MConfRankPrizePO::getRankNo, Boolean.TRUE);
            Map<Integer, List<MConfRankPrizePO>> listMap = prizePOS.stream().collect(Collectors.groupingBy(MConfRankPrizePO::getRankNo));
            List<MRankArcadeMachinePO> pos = mRankArcadeMachineDAO.findWeekRankList(startOfWeek, endOfWeek, param.getTimesType(), prizePOS.size());
            for (int i = 0; i < pos.size(); i++) {
                MRankArcadeMachinePO po = pos.get(i);
                List<MConfRankPrizePO> poList = listMap.get(i + 1);
                BaseRankVO vo = new BaseRankVO();
                UAppUserPO userPO = uAppUserDAO.findById(po.getUserId());
                vo.setNickName(userPO.getNickname());
                vo.setAvatarurl(userPO.getAvatarurl());
                vo.setVipGrade(po.getVipGrade());
                vo.setValue(po.getHighestPoints().toString());
                vo.setPrize(poList.get(0).getPinecone());
                vo.setRank(i + 1);
                if (po.getUserId().equals(currentUser.getUserId())) {
                    result.setIsRank(Boolean.TRUE);
                    result.setNickName(po.getNickname());
                    result.setAvatarurl(po.getAvatarurl());
                    result.setVipGrade(po.getVipGrade());
                    result.setValue(po.getHighestPoints().toString());
                    result.setPrize(poList.get(0).getPinecone());
                    result.setRank(i + 1);
                }
                rankVOS.add(vo);
            }
            result.setRankVOS(rankVOS);
            if (!result.getIsRank()) {
                MRankArcadeMachinePO myRank = mRankArcadeMachineDAO.findUserRank(startOfWeek, endOfWeek, param.getTimesType(), currentUser.getUserId());
                int myHighestPoints = Objects.isNull(myRank) ? 0 : myRank.getHighestPoints();
                BaseRankVO rankVO = null;
                if (CollectionUtils.isNotEmpty(rankVOS)) {
                    rankVO = rankVOS.get(rankVOS.size() - 1);
                }
                String diff = String.valueOf(Math.subtractExact(Integer.parseInt(Objects.isNull(rankVO) ? "0" : rankVO.getValue()), myHighestPoints));
                result.setDiff(diff);
            }
        } else if (WeekTypeEnum.yes_week.getCode().equals(param.getWeekType())) {
            List<MRankArcadeMachinePO> pos = mRankArcadeMachineDAO.findYesWeekRankList(startOfLastWeek, endOfLastWeek, param.getTimesType());
            pos.forEach(po -> {
                BaseRankVO vo = new BaseRankVO();
                vo.setNickName(po.getNickname());
                vo.setAvatarurl(po.getAvatarurl());
                vo.setVipGrade(po.getVipGrade());
                vo.setValue(po.getHighestPoints().toString());
                vo.setPrize(po.getGetPinecone());
                vo.setRank(po.getRankNo());
                if (po.getUserId().equals(currentUser.getUserId())) {
                    result.setIsRank(Boolean.TRUE);
                    result.setNickName(po.getNickname());
                    result.setAvatarurl(po.getAvatarurl());
                    result.setVipGrade(po.getVipGrade());
                    result.setValue(po.getHighestPoints().toString());
                    result.setPrize(po.getGetPinecone());
                    result.setRank(po.getRankNo());
                }
                rankVOS.add(vo);
            });
            result.setRankVOS(rankVOS);
        }
        return Result.success().data(result).build();
    }
}
